package info.motteke.kurumi.swt;

import info.motteke.kurumi.AnimationImage;

import java.util.Arrays;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;

public class SwtAnimationImage implements AnimationImage<Image> {

    private static final Log log = LogFactory.getLog(SwtAnimationImage.class);

    private final Frame<Image>[] frames;

    private int index = 0;

    private final int imageOffset;

    private final int width;

    private final int height;

    public SwtAnimationImage(ImageLoader animationGif, int imageOffset) {
        frames = createImages(animationGif);
        this.imageOffset = imageOffset;

        Rectangle size = frames[0].getImage().getBounds();
        width = size.width;
        height = size.height;

        log.info(frames.length + "個の画像を取得しました。");
    }

    private SwtAnimationFrame[] createImages(ImageLoader loader) {
        ImageData[] data = loader.data;
        Image[] images = new Image[data.length];
        SwtAnimationFrame[] frames = new SwtAnimationFrame[data.length];

        Device device = Display.getDefault();

        int width = loader.logicalScreenWidth;
        int height = loader.logicalScreenHeight;

        int transition = SWT.DM_FILL_BACKGROUND;

        for (int i = 0; i < data.length; i++) {
            Image base = new Image(device, width, height);
            ImageData id = data[i];
            GC gc = new GC(base);
            Color background = new Color(device, data[i].palette.colors[loader.backgroundPixel]);

            switch (transition) {
                case SWT.DM_FILL_NONE:
                    /* FALLTHROUGH */
                case SWT.DM_UNSPECIFIED:
                    /* FALLTHROUGH */
                case SWT.DM_FILL_PREVIOUS:
                    gc.drawImage(images[i - 1], 0, 0);
                    break;

                case SWT.DM_FILL_BACKGROUND:
                    gc.setBackground(background);
                    break;
            }

            Image image = new Image(device, data[i]);
            gc.drawImage(image, 0, 0, id.width, id.height, id.x, id.y, id.width, id.height);
            images[i] = base;
            background.dispose();
            gc.dispose();
            transition = id.disposalMethod;

            frames[i] = new SwtAnimationFrame(image, id.delayTime * 10);
        }

        return frames;
    }

    @Override
    public int getPeriod() {
        int sum = 0;
        for (Frame<Image> frame : frames) {
            sum += frame.getWait();
        }
        return sum;
    }

    @Override
    public synchronized void next() {
        index = (index + 1) % frames.length;
        log.info("インデックスを" + index + "に変更しました。");
    }

    @Override
    public synchronized Image getCurrentImage() {
        return frames[index].getImage();
    }

    @Override
    public List<Frame<Image>> getAllFrames() {
        return Arrays.asList(frames);
    }

    @Override
    public void dispose() {
        for (Frame<Image> frame : frames) {
            frame.dispose();
        }
    }

    public int getImageOffset() {
        return imageOffset;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }
}
